﻿using System;
using System.Diagnostics;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Microsoft.CodeMarkers.UnitTests
{
    [TestClass]
    public class Tests
    {
        [TestInitialize]
        public void InitializeTest()
        {
            CodeMarker.FreeResources();
        }

        [TestMethod]
        public void SimpleEndToEnd()
        {
            CodeMarker.InitializeService();
            CodeMarker.InitializeClient<TestMarker>(Process.GetCurrentProcess().Id);

            using (new CodeMarkerWaiter<TestMarker>(TestMarker.Start))
            {
                CodeMarker.Raise(TestMarker.Start);
            }
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void ExpectIOEWithoutInitializing()
        {
            using (new CodeMarkerWaiter<TestMarker>(TimeSpan.Zero, TestMarker.Start)) { }
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void NoMarkerSpecified()
        {
            CodeMarker.InitializeService();
            CodeMarker.InitializeClient<TestMarker>(Process.GetCurrentProcess().Id);

            using (new CodeMarkerWaiter<TestMarker>(TimeSpan.Zero)) { }
        }

        [TestMethod]
        [ExpectedException(typeof(TimeoutException))]
        public void WaiterTimeout()
        {
            CodeMarker.InitializeService();
            CodeMarker.InitializeClient<TestMarker>(Process.GetCurrentProcess().Id);

            using (new CodeMarkerWaiter<TestMarker>(TimeSpan.Zero, TestMarker.Start)) { }
        }

        [TestMethod]
        public void SampleAppTest()
        {
            // Simulate an application running in a different process
            SampleApp app = new SampleApp();
            Thread appThread = new Thread(app.Run);
            appThread.Start();

            CodeMarker.InitializeClient<TestMarker>(Process.GetCurrentProcess().Id);
            CodeMarker.WaitFor(TimeSpan.FromSeconds(10), TestMarker.Start);

            // Clean up app thread
            app.Stop();
            Assert.IsTrue(appThread.Join(1000));
        }
    }

    enum TestMarker
    {
        Start
    }

    public class SampleApp
    {
        ManualResetEvent RunningEvent { get; set; }

        public SampleApp()
        {
            CodeMarker.InitializeService();
            this.RunningEvent = new ManualResetEvent(false);
        }

        public void Run()
        {
            while (!this.RunningEvent.WaitOne(500))
            {
                CodeMarker.Raise<TestMarker>(TestMarker.Start);
            }
        }

        public void Stop()
        {
            this.RunningEvent.Set();
        }
    }
}